#include <stdio.h>
#include <string.h>

#include "record.h"

int 	l_int, r_int;
char 	l_str[MAX_STR_LENGTH], r_str[MAX_STR_LENGTH];

static int _check_condition(struct LIST *plList, struct LIST* plValue, struct OPNODE* root, int lr, int *iType)
{
	if (root->op == op_not)
	{
		int rret = _check_condition(plList, plValue, root->rchild, 1, iType);
		if (rret == -1)
			return -1;
		if (rret)
			return 0;
		else
			return 1;
	}
	else if (root->op == op_and || root->op == op_or)
	{
		int lret = _check_condition(plList, plValue, root->lchild, 0, iType);
		if (lret == -1)
			return -1;
		
		int rret = _check_condition(plList, plValue, root->rchild, 1, iType);

		if (rret == -1)
			return -1;
	
		if (root->op == op_and)
			return lret && rret;
		if (root->op == op_or)
			return lret || rret;
	}
	else if (root->op == eql || root->op == lss || root->op == leq || root->op == gtr || root->op == geq || root->op == neq)
	{
		int ltype;
		int lret = _check_condition(plList, plValue, root->lchild, 0, &ltype);
		if (lret == -1)
			return -1;

		int rtype;
		int rret = _check_condition(plList, plValue, root->rchild, 1, &rtype);
		if (rret == -1)
			return -1;

		if (ltype == INT_TYPE && rtype == INT_TYPE)
		{
			switch(root->op)
			{
#define _(oo) 	if (l_int oo r_int) \
					return 1; \
				else return 0; \
				break;
			case eql: _(==)
			case lss: _(<)
			case leq: _(<=)
			case gtr: _(>)
			case geq: _(>=)
			case neq: _(!=)
#undef _
			}
		}
		else if (ltype == STR_TYPE && rtype == STR_TYPE)
		{
			switch(root->op)
			{
#define _(oo) 	if (strcmp(l_str, r_str) oo 0) \
									return 1; \
								else return 0; \
								break;
				case eql: _(==)
				case lss: _(<)
				case leq: _(<=)
				case gtr: _(>)
				case geq: _(>=)
				case neq: _(!=)
#undef _
			}
		}
		return -1;
	}
	else
	{
		*iType = root->iType;
		if (root->iType == INT_TYPE)
		{
			if (lr == 0)
				l_int = *((int*)(root->pValue));
			else
				r_int = *((int*)(root->pValue));
		}
		else if (root->iType == STR_TYPE)
		{
			if (lr == 0)
				strcpy(l_str, (char*)(root->pValue));
			else
				strcpy(r_str, (char*)(root->pValue));
		}
		else
		{
			struct VARNODE* pNode = plList->pHead;
			struct VARNODE* pValue = plValue->pHead;

			while (pNode)
			{
				pNode = pNode->pNext;
				pValue = pValue->pNext;
				if (!strcmp((char*)(pNode->pValue), (char*)root->pValue))
				{
					if (pValue->iType == INT_TYPE)
					{
						if (lr == 0)
							l_int = *((int*)pValue->pValue);
						else
							r_int = *((int*)pValue->pValue);
					}
					else if (pValue->iType == STR_TYPE)
					{
						if (lr == 0)
							strcpy(l_str, (char*)(pValue->pValue));
						else
							strcpy(r_str, (char*)(pValue->pValue));
					}
					*iType = pValue->iType;
					break;
				}
			}
		}
		return 1;
	}
}

int insert_record(char* szTableName, struct LIST *plList)
{
	int i = 0, j = 0;
	char file_name[MAX_FILE_DIRECTORY] = BASE_DIRECTORY;
	strcat(file_name, "model");
	FILE *fp = NULL, *fpx = NULL;
	if ((fp = fopen(file_name, "rb")) == NULL)
	{
		fprintf(stderr, "Cannot open the model file!\n");
		return -1;
	}

	if (!check_table_exist(szTableName))
	{
		fprintf(stderr, "Table %s not exists!\n", szTableName);
		fclose(fp);
		return -1;
	}

	int position = find_table(fp, szTableName);
	if (position == -1)
	{
		fclose(fp);
		return -1;
	}
	
	struct TABLE table;
	fseek(fp, position, SEEK_SET);
	fread(&table, sizeof (struct TABLE), 1, fp);

	strcpy(file_name, DATA_DIRECTORY);
	strcat(file_name, szTableName);
	
	if ((fpx = fopen(file_name, "r+b")) == NULL)
	{
		fclose(fp);
		return -1;
	}

	struct BLOCK_INFO data_head;
	fseek(fpx, 0, SEEK_SET);
	fread(&data_head, sizeof (struct BLOCK_INFO), 1, fpx);

	struct VARNODE* pHead = plList->pHead;
	for (i = 0; i < table.iFieldNum; ++i)
	{
		pHead = pHead->pNext;
		if (pHead == NULL)
		{
			fprintf(stderr, "The number of fields doesn't match!\n");
			return -1;
		}
		else if (pHead->iType != table.sfaFields[i].iType)
		{
			fprintf(stderr, "The type of fields doesn't match!\n");
			return -1;
		}
	}
	if (pHead->pNext)
	{
		fprintf(stderr, "The number of fields doesn't match!\n");
		return -1;
	}

	while (j < data_head.iBlockNum)
	{
		pHead = plList->pHead;
		int flag = 1, mark = 0;
		char deld = 0;
		fread(&deld, sizeof (char), 1, fpx);
		for (i = 0; i < table.iFieldNum; ++i)
		{
			pHead = pHead->pNext;
			if (table.sfaFields[i].iType == INT_TYPE)
			{
				int tmp = 0;
				fread(&tmp, sizeof (int), 1, fpx);
				if (!deld && table.sfaFields[i].bIsKey == 1)
				{
					mark = 1;
					if (tmp != *((int*)(pHead->pValue)))
						flag = 0;
				}
			}
			else if (table.sfaFields[i].iType == STR_TYPE)
			{
				char tmp[MAX_STR_LENGTH];
				fread(tmp, sizeof (char) * (table.sfaFields[i].iLength), 1, fpx);

				if (!deld && table.sfaFields[i].bIsKey == 1)
				{
					mark = 1;
					if (strcmp(tmp, (char*)(pHead->pValue)))
						flag = 0;
				}
			}
		}
		if (mark == 1 && flag == 1)
		{
			fprintf(stderr, "Conflict Key!\n");
			fclose(fp);
			fclose(fpx);
			return -1;
		}
		if (!deld)
			++j;
	}

	pHead = plList->pHead;
	char deld = 0;
	fwrite(&deld, sizeof (char), 1, fpx);
	for (i = 0; i < table.iFieldNum; ++i)
	{
		pHead = pHead->pNext;
		if (pHead->iType == INT_TYPE)
		{
			fwrite((int*)(pHead->pValue), sizeof (int), 1, fpx);
			printf("%d ", *((int*)(pHead->pValue)));
		}
		else if (pHead->iType == STR_TYPE)
		{
			fwrite((char*)(pHead->pValue), sizeof (char) * (table.sfaFields[i].iLength), 1, fpx);
			printf("%s ", (char*)(pHead->pValue));
		}
	}
	putchar('\n');
	
	fseek(fpx, 0, SEEK_SET);
	data_head.iBlockNum++;
	fwrite(&data_head, sizeof (struct BLOCK_INFO), 1, fpx);

	fclose(fp);
	fclose(fpx);
	return 1;
}

int delete_record(char *szTableName, struct OPNODE* root)
{
	int i = 0, j = 0;
	int cnt = 0;
	char file_name[MAX_FILE_DIRECTORY] = BASE_DIRECTORY;
	strcat(file_name, "model");
	FILE *fp = NULL, *fpx = NULL;

	if ((fp = fopen(file_name, "r+b")) == NULL)
	{
		fprintf(stderr, "Cannot open the model file!\n");
		return -1;
	}

	if (!check_table_exist(szTableName))
	{
		fprintf(stderr, "Table %s not exists!\n", szTableName);
		fclose(fp);
		return -1;
	}

	int position = find_table(fp, szTableName);
	if (position == -1)
	{
		fclose(fp);
		return -1;
	}

	struct TABLE table;
	fseek(fp, position, SEEK_SET);
	fread(&table, sizeof (struct TABLE), 1, fp);
	
	strcpy(file_name, DATA_DIRECTORY);
	strcat(file_name, szTableName);

	if ((fpx = fopen(file_name, "r+b")) == NULL)
	{
		fclose(fp);
		return -1;
	}

	struct LIST *plAttribute = l_create();
	position = sizeof (char);
	for (i = 0; i < table.iFieldNum; ++i)
	{
		if (table.sfaFields[i].iType == INT_TYPE)
			position += sizeof (int);
		else if (table.sfaFields[i].iType == STR_TYPE)
			position += sizeof (char) * table.sfaFields[i].iLength;
		l_append(plAttribute, STR_TYPE, table.sfaFields[i].szFieldName);
	}

	struct BLOCK_INFO data_head;
	fseek(fpx, 0, SEEK_SET);
	fread(&data_head, sizeof (struct BLOCK_INFO), 1, fpx);
	
	struct LIST *plList;
	while (j < data_head.iBlockNum)
	{
		char deld;
		plList = l_create();
		fread(&deld, sizeof (char), 1, fpx);
		for (i = 0; i < table.iFieldNum; ++i)
		{
			if (table.sfaFields[i].iType == INT_TYPE)
			{
				int tmp = 0;
				fread(&tmp, sizeof (int), 1, fpx);
				if (!deld)
					l_append(plList, INT_TYPE, &tmp);
			}
			else if (table.sfaFields[i].iType == STR_TYPE)
			{
				char tmp[MAX_STR_LENGTH];
				fread(tmp, sizeof (char) * (table.sfaFields[i].iLength), 1, fpx);
				if (!deld)
					l_append(plList, STR_TYPE, &tmp);
			}
		}
		if (!deld)
			++j;
		int tType;
		if (_check_condition(plAttribute, plList, root, 0, &tType) == 1)
		{
			fseek(fpx, -position, SEEK_CUR);
			deld = 1;
			fwrite(&deld, sizeof (char), 1, fpx);
			fseek(fpx, position - sizeof (char), SEEK_CUR);
			++cnt;
		}
		l_release(plList);
	}

	data_head.iBlockNum -= cnt;
	fseek(fpx, 0, SEEK_SET);
	fwrite(&data_head, sizeof (struct BLOCK_INFO), 1, fpx);

	fclose(fp);
	fclose(fpx);
	return 1;
}

char 	fname[MAX_FIELD_NUM][MAX_FIELD_NAME_LEN];
int 	fpos[MAX_FIELD_NUM];
int 	ftype[MAX_FIELD_NUM];
int 	nfpos;

int select_record(char* szTableName, struct LIST *plList, OPNODE* root, int iFlag)
{
	char file_name[MAX_FILE_DIRECOTRY] = BASE_DIRECTORY;
	strcat(file_name, "temp");
	FILE *fpt = fopen(temp_name, "w+b");
	if (fpt == NULL)
	{
		fprintf(stderr, "Cannot open the temp file!\n");
		return -1;
	}

	int i = 0;
	strcpy(file_name, BASE_DIRECTORY);
	strcat(file_name, "model");
	FILE *fp = NULL, *fpx = NULL;
	if ((fp = fopen(model, "r+b")) == NULL)
	{
		fprintf(stderr, "Cannot open the model file!\n");
		return -1;
	}
	if (!check_exist_table(szTableName))
	{
		fprintf(stderr, "Table %s not exists!\n");
		fclose(fp);
		return -1;
	}

	int position = find_table(fp, szTableName);
	if (position == -1)
	{
		fclose(fp);
		return -1;
	}
	
	strcpy(file_name, DATA_DIRECTORY);
	strcat(file_name, szTableName);

	if ((fpx = fopen(file_name, "r+b")) == NULL)
	{
		fclose(fp);
		return -1;
	}

	struct TABLE table;
	fseek(fp, position, SEEK_SET);
	fread(&table, sizeof (struct TABLE), 1, fp);

	struct BLOCK_INFO data_head;
	fseek(fpx, 0, SEEK_SET);
	fread(&data_head, sizeof (struct BLOCK_INFO), 1, fpx);

	struct VARNODE* pHead = plList->pHead;

	nfpos = 0;
	int all = 0, type;
	while (pHead)
	{
		pHead = pHead->pNext;
		if (!strcmp("*", (char*)(pHead->pValue)))
		{
			all = 1;
			break;
		}
		int t = find_field(table, (char*)(pHead->pValue), &type);

		if (t == -1)
			return -1;

		strcpy(fname[nfpos], (char*)(pHead->pValue));
		fpos[nfpos] = t;
		ftype[nfpos++] = type;
	}

	if (all == 0)
	{
		for (i = 0; i < nfpos; ++i)

